package cn.zhongzhi.sm2;

import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Base64;

import java.io.File;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * *********************************
 * SM2Util
 * whoever
 * Create By HuangBo
 * Create On 2023/5/18 10:19
 * *********************************
 *
 * @author huangbo*/
public class Sm2Util {

    private ECPoint publicKey;
    private BigInteger privateKey;

    public Sm2Util(){
    }

    /**
     * 生成SM2秘钥对
     * @return
     */
    public SM2KeyPair generateKeyPair(){
        return SM2.generateKeyPair();
    }

    /**
     * 生成的秘钥对变成字符串
     * map.get("publicKey")
     * map.get("privateKey")
     * @return
     */
    public Map<String, String> sm2KeyPair2Map(SM2KeyPair sm2KeyPair){
        ECPoint publicKey = sm2KeyPair.getPublicKey();
        BigInteger privateKey = sm2KeyPair.getPrivateKey();
        Map<String, String> map = new HashMap<>();
        map.put("publicKey", SM2.getPublicKeyInString(publicKey));
        map.put("privateKey", SM2.getPrivateKeyInString(privateKey));
        return map;
    }

    /**
     * 初始化文件公钥
     * @param file 文件
     */
    public void initPublicKey(File file) {
        this.publicKey = SM2.importPublicKey(file);
    }

    /**
     * 初始化文件私钥
     * @param file 文件
     */
    public void initPrivateKey(File file) {
        this.privateKey = SM2.importPrivateKey(file);
    }

    /**
     * 导入文件公钥
     * @param file 文件
     * @return {@link ECPoint}
     */
    public ECPoint importPublicKey(File file) {
        return SM2.importPublicKey(file);
    }

    /**
     * 导入文件私钥
     * @param file 文件
     * @return {@link BigInteger}
     */
    public BigInteger importPrivateKey(File file) {
        return SM2.importPrivateKey(file);
    }

    /**
     * 导出公钥到文件
     * @param publicKey 公钥
     * @param file      文件
     */
    public void exportPublicKey(ECPoint publicKey, File file) {
        SM2.exportPublicKey(publicKey,file);
    }

    /**
     * 导出私钥到文件
     * @param privateKey 私钥
     * @param file       文件
     */
    public void exportPrivateKey(BigInteger privateKey, File file) {
        SM2.exportPrivateKey(privateKey, file);
    }

    /**
     * SM2加密
     * @param data
     * @return
     */
    public String encryptSm2(String data){
        String base64String = Base64.toBase64String(data.getBytes(StandardCharsets.UTF_8));
        byte[] encrypt = SM2.encrypt(base64String, publicKey);
        return Base64.toBase64String(encrypt);
    }

    /**
     * SM2解密
     * @param data
     * @return
     */
    public String decryptSm2(String data) {
        byte[] decode = Base64.decode(data.getBytes(StandardCharsets.UTF_8));
        byte[] decrypt = SM2.decrypt(decode, privateKey);
        return new String(Base64.decode(decrypt),StandardCharsets.UTF_8);
    }

    /**
     * SM2加密
     * @param data
     * @param publicKey
     * @return
     */
    public String encryptSm2(String data, ECPoint publicKey){
        byte[] encrypt = SM2.encrypt(Base64.toBase64String(data.getBytes(StandardCharsets.UTF_8)), publicKey);
        return Base64.toBase64String(encrypt);
    }

    /**
     * SM2解密
     * @param data
     * @param privateKey
     * @return
     */
    public String decryptSm2(String data, BigInteger privateKey) {
        byte[] decode = Base64.decode(data.getBytes(StandardCharsets.UTF_8));
        byte[] decrypt = SM2.decrypt(decode, privateKey);
        return new String(Base64.decode(decrypt),StandardCharsets.UTF_8);
    }

    /**
     * SM2加密
     *
     * @param data
     * @param publicKey
     * @return
     */
    public String encryptSm2(String data, String publicKey, boolean isBase64Key) {
        if (isBase64Key) {
            ECPoint ecPoint = convertPublicKey(publicKey);
            return encryptSm2(data, ecPoint);
        } else {
            return encryptSm2(data, publicKey);
        }
    }

    /**
     * SM2加密
     * @param data
     * @param publicKey
     * @return
     */
    public String encryptSm2(String data, String publicKey) {
        String base64String = Base64.toBase64String(data.getBytes(StandardCharsets.UTF_8));
        byte[] encrypt = SM2.encrypt(base64String, SM2.getPublicKeyInECPoint(publicKey));
        return Base64.toBase64String(encrypt);
    }

    /**
     * SM2解密
     * @param data
     * @param privateKey
     * @return
     */
    public String decryptSm2(String data, String privateKey) {
        byte[] decode = Base64.decode(data.getBytes(StandardCharsets.UTF_8));
        byte[] decrypt = SM2.decrypt(decode, SM2.getPrivateKeyInBigInteger(privateKey));
        return new String(Base64.decode(decrypt),StandardCharsets.UTF_8);
    }

    /**
     * 公钥解码
     * @param base64PublicKey
     * @return
     */
    public ECPoint convertPublicKey(String base64PublicKey){
        byte[] publicKey = Base64.decode(base64PublicKey.getBytes(StandardCharsets.UTF_8));
        ECPoint convertPublicKey = SM2.convertPublicKey(new String(publicKey, StandardCharsets.UTF_8));
        return convertPublicKey;
    }

    /**
     * 签名者签名过程
     * @param M 签名信息 String
     * @param IDA 签名方标识 String
     * @param keyPair 签名方公钥私钥密钥对 SM2KeyPair
     * @return 签名 Signature
     */
    public String sign(String M, String IDA, SM2KeyPair keyPair) {
        return SM2.sign(M, IDA, keyPair).toString();
    }

    /**
     * 验证方验签
     * @param M 签名信息 String
     * @param signatureStr 签名 Signature
     * @param IDA 签名方标识 String
     * @param publicKey 签名方公钥 ECPoint
     * @return 结果 true or false
     */
    public boolean verify(String M, String signatureStr, String IDA, ECPoint publicKey) {
        String[] split = signatureStr.split(",");
        SM2.Signature signature = new SM2.Signature(new BigInteger(split[0], 16), new BigInteger(split[1], 16));
        return SM2.verify(M, signature, IDA, publicKey);
    }

}
